package com.kinyx.framework.file;

import com.kinyx.framework.annotation.assist.CanNotNull;
import com.kinyx.framework.annotation.assist.CanNull;
import com.kinyx.framework.annotation.assist.ReturnNotNull;
import com.kinyx.framework.annotation.assist.ReturnNull;
import com.kinyx.framework.annotation.assist.Tester;
import com.kinyx.framework.constraints.URL;
import com.kinyx.framework.constraints.WindowsPath;
import com.kinyx.framework.utils.KMatcherUtils;
import com.kinyx.framework.utils.KStringUtils;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

/**
 * 路径工具类
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class KPathUtils {

	/** 包名分隔符 */
	private static final String PACKAGE_SPLITOR = "\\.";
	/** 路径分隔符 */
	private static final String PATH_SPLITOR = "/";
	/** 路径分隔符 */
	private static final String PATH_SPLITOR2 = "\\\\";

	/**
	 * 判断是否为Windows全路径
	 * @param str 字符串
	 * @return true：是Windows全路径；false：非Windows全路径；
	 */
	@ReturnNotNull
	public static boolean isWindowsPath(@CanNull final String str) {
		if (str == null) { return false; }
		return KMatcherUtils.matches(str, WindowsPath.REGEX);
	}

	/**
	 * 判断是否为URL
	 * @param str 字符串
	 * @return true：是URL；false：非URL；
	 */
	@ReturnNotNull
	@Tester("com.kinyx.framework.file.KPathUtils_Tester_isURL")
	public static boolean isURL(@CanNull final String str) {
		if (str == null) { return false; }
		return KMatcherUtils.matches(str, URL.REGEX);
	}

	/**
	 * 转换为标准路径
	 * <pre>
		Assert.assertEquals(null, KPathUtils.toPath(null));
		Assert.assertEquals(null, KPathUtils.toPath("null"));
	
		Assert.assertEquals("/", KPathUtils.toPath(""));
		Assert.assertEquals("/", KPathUtils.toPath(" "));
	
		Assert.assertEquals("/null", KPathUtils.toPath(" null "));
		Assert.assertEquals("/foo", KPathUtils.toPath("foo"));
		Assert.assertEquals("/foo", KPathUtils.toPath(" foo "));
	
		Assert.assertEquals("http://www.kinyx.com", KPathUtils.toPath("http://www.kinyx.com"));
		Assert.assertEquals("https://www.kinyx.com", KPathUtils.toPath("https://www.kinyx.com"));
		Assert.assertEquals("ftp://www.kinyx.com", KPathUtils.toPath("ftp://www.kinyx.com"));
	
		Assert.assertEquals("c:/kinyx", KPathUtils.toPath("c:/kinyx"));
		Assert.assertEquals("c:/kinyx", KPathUtils.toPath("/c:/kinyx"));
		Assert.assertEquals("C:/kinyx", KPathUtils.toPath("C:/kinyx"));
		Assert.assertEquals("C:/kinyx", KPathUtils.toPath("/C:/kinyx"));
	
		Assert.assertEquals("/com/kinyx/framework/file/KPathUtils", KPathUtils.toPath("com/kinyx/framework/file/KPathUtils"));
		Assert.assertEquals("/com/kinyx/framework/file/KPathUtils", KPathUtils.toPath("com\\kinyx\\framework\\file\\KPathUtils"));
	
		Assert.assertEquals("/com/kinyx/framework/file/KPathUtils", KPathUtils.toPath("/com/kinyx/framework/file/KPathUtils"));
		Assert.assertEquals("/com/kinyx/framework/file/KPathUtils", KPathUtils.toPath("\\com\\kinyx\\framework\\file\\KPathUtils"));
	
		Assert.assertEquals("/com/kinyx/framework/file/KPathUtils", KPathUtils.toPath("com/kinyx/framework/file/KPathUtils/"));
		Assert.assertEquals("/com/kinyx/framework/file/KPathUtils", KPathUtils.toPath("com\\kinyx\\framework\\file\\KPathUtils\\"));
	
		Assert.assertEquals("/com/kinyx/framework/file/KPathUtils", KPathUtils.toPath("/com/kinyx/framework/file/KPathUtils/"));
		Assert.assertEquals("/com/kinyx/framework/file/KPathUtils", KPathUtils.toPath("\\com\\kinyx\\framework\\file\\KPathUtils\\"));
	 * </pre>
	 * @param str 字符串
	 * @return 路径（有前缀"/"，无后缀"/"，且所有分隔符都将使用"/"。）
	 */
	@ReturnNull("str == null")
	@ReturnNull("str.equals('null')")
	@Tester("com.kinyx.framework.file.KPathUtils_Tester_toPath")
	public static String toPath(@CanNull final String str) {
		final String result = KStringUtils.operate(str, s -> {
			s = s.trim();
			if (s.equals("")) { return ""; }
			if (isURL(s)) { return s; }
			// 统一分隔符
			s = s.replaceAll(PATH_SPLITOR2, PATH_SPLITOR);
			// 补充前缀
			if (!s.startsWith(PATH_SPLITOR)) { s = PATH_SPLITOR + s; }
			// 带前缀的Windows路径去除前缀
			if (KMatcherUtils.matches(s, PATH_SPLITOR + WindowsPath.REGEX)) { s = s.substring(1); }
			// 去除后缀
			return s.endsWith(PATH_SPLITOR) ? s.substring(0, s.length() - 1) : s;
		});
		if ("".equals(result)) { return PATH_SPLITOR; }
		return result;
	}

	/**
	 * 替换包名分隔符为路径分隔符
	 * <pre>
		Assert.assertEquals(null, KPathUtils.package2path(null));
		Assert.assertEquals(null, KPathUtils.package2path("null"));
	
		Assert.assertEquals("/", KPathUtils.package2path(""));
		Assert.assertEquals("/", KPathUtils.package2path(" "));
	
		Assert.assertEquals("/null", KPathUtils.package2path(" null "));
		Assert.assertEquals("/foo", KPathUtils.package2path("foo"));
		Assert.assertEquals("/foo", KPathUtils.package2path(" foo "));
	
		Assert.assertEquals("/com/kinyx/framework/file/KPathUtils", KPathUtils.package2path("com.kinyx.framework.file.KPathUtils"));
	 * </pre>
	 * @param str 字符串
	 * @return 字符串
	 */
	@ReturnNull("str == null")
	@ReturnNull("str.equals('null')")
	@Tester("com.kinyx.framework.file.KPathUtils_Tester_package2path")
	public static String package2path(@CanNull final String str) {
		return KStringUtils.operate(toPath(str), s -> {
			return s.replaceAll(PACKAGE_SPLITOR, PATH_SPLITOR);
		});
	}

	/**
	 * 替路径分隔符为包名分隔符
	 * <pre>
		Assert.assertEquals(null, KPathUtils.path2package(null));
		Assert.assertEquals(null, KPathUtils.path2package("null"));
	
		Assert.assertEquals("", KPathUtils.path2package(""));
		Assert.assertEquals("", KPathUtils.path2package(" "));
	
		Assert.assertEquals("null", KPathUtils.path2package(" null "));
		Assert.assertEquals("foo", KPathUtils.path2package("foo"));
		Assert.assertEquals("foo", KPathUtils.path2package(" foo "));
	
		Assert.assertEquals("com.kinyx.framework.file.KPathUtils", KPathUtils.path2package("com/kinyx/framework/file/KPathUtils"));
		Assert.assertEquals("com.kinyx.framework.file.KPathUtils", KPathUtils.path2package("com\\kinyx\\framework\\file\\KPathUtils"));
	
		Assert.assertEquals("com.kinyx.framework.file.KPathUtils", KPathUtils.path2package("/com/kinyx/framework/file/KPathUtils"));
		Assert.assertEquals("com.kinyx.framework.file.KPathUtils", KPathUtils.path2package("\\com\\kinyx\\framework\\file\\KPathUtils"));
	
		Assert.assertEquals("com.kinyx.framework.file.KPathUtils", KPathUtils.path2package("com/kinyx/framework/file/KPathUtils/"));
		Assert.assertEquals("com.kinyx.framework.file.KPathUtils", KPathUtils.path2package("com\\kinyx\\framework\\file\\KPathUtils\\"));
	
		Assert.assertEquals("com.kinyx.framework.file.KPathUtils", KPathUtils.path2package("/com/kinyx/framework/file/KPathUtils/"));
		Assert.assertEquals("com.kinyx.framework.file.KPathUtils", KPathUtils.path2package("\\com\\kinyx\\framework\\file\\KPathUtils\\"));
	 * </pre>
	 * @param str 字符串
	 * @return 字符串
	 */
	@ReturnNull("str == null")
	@ReturnNull("str.equals('null')")
	@Tester("com.kinyx.framework.file.KPathUtils_Tester_path2package")
	public static String path2package(@CanNull final String str) {
		return KStringUtils.operate(toPath(str), s -> {
			return s.substring(1).replaceAll(PATH_SPLITOR, PACKAGE_SPLITOR);
		});
	}

	/** 取编译根路径 */
	private static String rootPath() { return toPath(ClassLoader.getSystemResource("").getPath()); }
	/** MAVEN项目：编译路径 */
	private static final String TARGET = "target";
	/** MAVEN项目：编译路径 */
	private static final String TARGET_CLASSES = "target/classes";
	/** MAVEN项目：测试编译路径 */
	private static final String TARGET_TEST_CLASSES = "target/test-classes";
	/** MAVEN项目：源码路径 */
	private static final String SRC_MAIN_JAVA = "src/main/java";
	/** MAVEN项目：测试源码路径 */
	private static final String SRC_TEST_JAVA = "src/test/java";
	/** MAVEN项目：资源路径 */
	private static final String SRC_MAIN_RESOURCES = "src/main/resources";
	/** MAVEN项目：测试资源路径 */
	private static final String SRC_TEST_RESOURCES = "src/test/resources";

	/** @return true：测试目录；false：正式目录； */
	public static boolean test() {
		return rootPath().contains(TARGET_TEST_CLASSES);
	}

	/**
	 * 获取MAVEN项目源码路径
	 * @param test true：src/test/java；false：src/main/java；
	 * @return 源码路径
	 */
	@ReturnNotNull
	public static String java(@CanNotNull final boolean test) {
		String rootPath = rootPath();
		if (rootPath.contains(TARGET_CLASSES)) {
			rootPath = rootPath.replace(TARGET_CLASSES, test ? SRC_TEST_JAVA : SRC_MAIN_JAVA);
		} else if (rootPath.contains(TARGET_TEST_CLASSES)) {
			rootPath = rootPath.replace(TARGET_TEST_CLASSES, test ? SRC_TEST_JAVA : SRC_MAIN_JAVA);
		}
		return toPath(rootPath);
	}

	/**
	 * 获取MAVEN项目资源路径
	 * @param test true：src/test/resources；false：src/main/resources；
	 * @return 资源路径
	 */
	@ReturnNotNull
	public static String resources(@CanNotNull final boolean test) {
		String rootPath = rootPath();
		if (rootPath.contains(TARGET_CLASSES)) {
			rootPath = rootPath.replace(TARGET_CLASSES, test ? SRC_TEST_RESOURCES : SRC_MAIN_RESOURCES);
		} else if (rootPath.contains(TARGET_TEST_CLASSES)) {
			rootPath = rootPath.replace(TARGET_TEST_CLASSES, test ? SRC_TEST_RESOURCES : SRC_MAIN_RESOURCES);
		}
		return toPath(rootPath);
	}

	/**
	 * 获取MAVEN项目编译路径
	 * @return 编译路径
	 */
	@ReturnNotNull
	public static String target() {
		String rootPath = rootPath();
		if (rootPath.contains(TARGET_CLASSES)) {
			rootPath = rootPath.replace(TARGET_CLASSES, TARGET);
		} else if (rootPath.contains(TARGET_TEST_CLASSES)) {
			rootPath = rootPath.replace(TARGET_TEST_CLASSES, TARGET);
		}
		return toPath(rootPath);
	}

}
